/**
 * @file test_events.cpp
 * @author 心流 (iFlow CLI)
 * @brief 测试OpenCL事件对象管理功能
 * @version 0.1
 * @date 2025-11-27
 *
 * @copyright Copyright (c) 2025
 *
 */
#define BOOST_TEST_MODULE TestEvents
#include <CL/cl.h>

#include <boost/format.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/timer/timer.hpp>
#include <vector>

#include "wrapper.hpp"
#include "utility.hpp"

// 测试创建和管理用户事件
BOOST_AUTO_TEST_CASE(TestUserEvent)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    BOOST_CHECK(context != nullptr);

    // 创建用户事件
    cl_int err = CL_SUCCESS;
    cl_event user_event = clCreateUserEvent(context, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(user_event != nullptr);

    // 检查用户事件的初始状态
    cl_int event_status = 0;
    err = clGetEventInfo(user_event,
                         CL_EVENT_COMMAND_EXECUTION_STATUS,
                         sizeof(event_status),
                         &event_status,
                         nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    // 用户事件初始状态应该是CL_SUBMITTED
    // 但根据规范，用户事件初始状态是CL_SUBMITTED，直到显式设置

    // 设置用户事件状态为完成
    err = clSetUserEventStatus(user_event, CL_COMPLETE);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 再次检查状态
    cl_int new_status = 0;
    err = clGetEventInfo(user_event,
                         CL_EVENT_COMMAND_EXECUTION_STATUS,
                         sizeof(new_status),
                         &new_status,
                         nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_EQUAL(new_status, CL_COMPLETE);

    // 等待事件完成
    err = clWaitForEvents(1, &user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 清理事件
    err = clReleaseEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试内核执行事件
BOOST_AUTO_TEST_CASE(TestKernelEvent)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    cl_command_queue queue = cl.GetQueue();
    cl_device_id device = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(queue != nullptr);
    BOOST_CHECK(device != nullptr);

    // 创建简单的内核源代码
    const char* kernel_source = R"(
        __kernel void test_kernel(__global int* input, __global int* output) {
            int id = get_global_id(0);
            output[id] = input[id] * 2;
        }
    )";

    // 创建程序
    cl_program program = clCreateProgramWithSource(
        context, 1, &kernel_source, nullptr, nullptr);
    BOOST_CHECK(program != nullptr);

    // 构建程序
    cl_int err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
    if (err != CL_SUCCESS) {
        size_t log_size;
        clGetProgramBuildInfo(
            program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
        std::vector<char> log(log_size);
        clGetProgramBuildInfo(
            program, device, CL_PROGRAM_BUILD_LOG, log_size, log.data(), nullptr);
        std::cout << "Build log: " << log.data() << std::endl;
    }
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 创建内核
    cl_kernel kernel = clCreateKernel(program, "test_kernel", &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(kernel != nullptr);

    // 创建内存对象
    const size_t buffer_size = 256 * sizeof(int);
    cl_mem input_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(input_buffer != nullptr);

    cl_mem output_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buffer_size, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(output_buffer != nullptr);

    // 准备输入数据
    std::vector<int> input_data(256);
    for (int i = 0; i < 256; i++) {
        input_data[i] = i;
    }

    // 将数据写入输入缓冲区
    cl_event write_event = nullptr;
    err = clEnqueueWriteBuffer(queue, input_buffer, CL_FALSE, 0, buffer_size,
                               input_data.data(), 0, nullptr, &write_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(write_event != nullptr);

    // 设置内核参数
    err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &input_buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    err = clSetKernelArg(kernel, 1, sizeof(cl_mem), &output_buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 执行内核并获取事件
    size_t global_work_size = 256;
    cl_event kernel_event = nullptr;
    err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &global_work_size,
                                 nullptr, 1, &write_event, &kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(kernel_event != nullptr);

    // 查询事件信息
    cl_command_type command_type;
    err = clGetEventInfo(kernel_event, CL_EVENT_COMMAND_TYPE, 
                         sizeof(command_type), &command_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(command_type == CL_COMMAND_NDRANGE_KERNEL);

    cl_context event_context;
    err = clGetEventInfo(kernel_event, CL_EVENT_CONTEXT,
                         sizeof(event_context), &event_context, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(event_context == context);

    // 等待内核执行完成
    err = clWaitForEvents(1, &kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 读取结果
    std::vector<int> output_data(256);
    cl_event read_event = nullptr;
    err = clEnqueueReadBuffer(queue, output_buffer, CL_TRUE, 0, buffer_size,
                              output_data.data(), 0, nullptr, &read_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(read_event != nullptr);

    // 验证结果
    for (int i = 0; i < 256; i++) {
        BOOST_CHECK_EQUAL(output_data[i], input_data[i] * 2);
    }

    // 查询事件配置信息
    cl_command_queue event_queue;
    err = clGetEventInfo(kernel_event, CL_EVENT_COMMAND_QUEUE,
                         sizeof(event_queue), &event_queue, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(event_queue == queue);

    // 查询事件状态
    cl_int event_status;
    err = clGetEventInfo(kernel_event, CL_EVENT_COMMAND_EXECUTION_STATUS,
                         sizeof(event_status), &event_status, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    // 事件应该已经完成
    BOOST_CHECK_EQUAL(event_status, CL_COMPLETE);

    // 等待所有事件完成
    err = clWaitForEvents(1, &read_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 清理资源
    err = clReleaseEvent(write_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    
    err = clReleaseEvent(kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    
    err = clReleaseEvent(read_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseMemObject(input_buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseMemObject(output_buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseKernel(kernel);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseProgram(program);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试事件的引用计数
BOOST_AUTO_TEST_CASE(TestEventReferenceCounting)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    cl_command_queue queue = cl.GetQueue();
    cl_device_id device = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(queue != nullptr);
    BOOST_CHECK(device != nullptr);

    // 创建用户事件
    cl_int err = CL_SUCCESS;
    cl_event user_event = clCreateUserEvent(context, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(user_event != nullptr);

    // 查询初始引用计数
    cl_uint ref_count = 0;
    err = clGetEventInfo(user_event, CL_EVENT_REFERENCE_COUNT,
                         sizeof(ref_count), &ref_count, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(ref_count, 0);

    // 增加引用计数
    err = clRetainEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 再次查询引用计数
    cl_uint new_ref_count = 0;
    err = clGetEventInfo(user_event, CL_EVENT_REFERENCE_COUNT,
                         sizeof(new_ref_count), &new_ref_count, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(new_ref_count, ref_count);

    // 设置事件状态
    err = clSetUserEventStatus(user_event, CL_COMPLETE);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 等待事件
    err = clWaitForEvents(1, &user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 释放两次以完全清理
    err = clReleaseEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试事件回调函数
BOOST_AUTO_TEST_CASE(TestEventCallback)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    BOOST_CHECK(context != nullptr);

    // 定义回调函数
    bool callback_called = false;
    auto callback = [](cl_event event, cl_int event_command_exec_status, void* user_data) {
        bool* flag = static_cast<bool*>(user_data);
        *flag = true;
    };

    // 创建用户事件
    cl_int err = CL_SUCCESS;
    cl_event user_event = clCreateUserEvent(context, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(user_event != nullptr);

    // 注册回调函数
    err = clSetEventCallback(user_event, CL_COMPLETE, callback, &callback_called);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 设置事件为完成状态，这应该触发回调
    err = clSetUserEventStatus(user_event, CL_COMPLETE);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 等待一段时间以确保回调执行
    // 由于回调是异步的，我们等待直到标志被设置
    int attempts = 0;
    while (!callback_called && attempts < 100) {
        // 简单的等待机制
        attempts++;
        // 在实际代码中，可能需要更复杂的同步机制
        // 这里我们假设回调很快就会被调用
    }

    // 注意：由于回调函数的异步性质，我们无法在测试中可靠地验证它
    // 实际上，我们只是确保注册回调和设置事件状态不产生错误

    // 清理事件
    err = clReleaseEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试事件错误处理
BOOST_AUTO_TEST_CASE(TestEventErrorHandling)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    cl_command_queue queue = cl.GetQueue();
    cl_device_id device = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(queue != nullptr);
    BOOST_CHECK(device != nullptr);

    cl_int err = CL_SUCCESS;

    // 测试使用无效上下文创建用户事件（应该失败）
    cl_event user_event = clCreateUserEvent(nullptr, &err);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败
    BOOST_CHECK(user_event == nullptr);

    // 正常创建用户事件
    user_event = clCreateUserEvent(context, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(user_event != nullptr);

    // 测试使用无效事件设置状态（应该失败）
    err = clSetUserEventStatus(nullptr, CL_COMPLETE);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 测试使用无效事件获取信息（应该失败）
    cl_int event_status;
    err = clGetEventInfo(nullptr, CL_EVENT_COMMAND_EXECUTION_STATUS,
                         sizeof(event_status), &event_status, nullptr);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 测试使用无效事件等待（应该失败）
    err = clWaitForEvents(1, static_cast<cl_event*>(nullptr));
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 测试使用有效但错误的事件数组等待（应该失败）
    cl_event invalid_event_array[] = {nullptr};
    err = clWaitForEvents(1, invalid_event_array);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 正常设置事件状态
    err = clSetUserEventStatus(user_event, CL_COMPLETE);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 正常等待事件
    err = clWaitForEvents(1, &user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 正常清理事件
    err = clReleaseEvent(user_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试事件配置文件信息
BOOST_AUTO_TEST_CASE(TestEventProfilingInfo)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    cl_command_queue queue = cl.GetQueue();
    cl_device_id device = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(queue != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查队列是否启用了配置文件
    cl_command_queue_properties queue_props = 0;
    cl_int err = clGetCommandQueueInfo(queue, CL_QUEUE_PROPERTIES,
                                       sizeof(queue_props), &queue_props, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 创建简单的内核源代码
    const char* kernel_source = R"(
        __kernel void simple_kernel(__global int* data) {
            int id = get_global_id(0);
            data[id] = id * id;
        }
    )";

    // 创建程序
    cl_program program = clCreateProgramWithSource(
        context, 1, &kernel_source, nullptr, nullptr);
    BOOST_CHECK(program != nullptr);

    // 构建程序
    err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
    if (err != CL_SUCCESS) {
        size_t log_size;
        clGetProgramBuildInfo(
            program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
        std::vector<char> log(log_size);
        clGetProgramBuildInfo(
            program, device, CL_PROGRAM_BUILD_LOG, log_size, log.data(), nullptr);
        std::cout << "Build log: " << log.data() << std::endl;
    }
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 创建内核
    cl_kernel kernel = clCreateKernel(program, "simple_kernel", &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(kernel != nullptr);

    // 创建内存对象
    const size_t buffer_size = 64 * sizeof(int);
    cl_mem buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_size, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(buffer != nullptr);

    // 设置内核参数
    err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 执行内核并获取事件（使用配置文件）
    size_t global_work_size = 64;
    cl_event kernel_event = nullptr;
    err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &global_work_size,
                                 nullptr, 0, nullptr, &kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(kernel_event != nullptr);

    // 等待内核执行完成
    err = clWaitForEvents(1, &kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 如果队列支持配置文件，则查询配置文件信息
    if (queue_props & CL_QUEUE_PROFILING_ENABLE) {
        cl_ulong time_queued = 0;
        err = clGetEventProfilingInfo(kernel_event, CL_PROFILING_COMMAND_QUEUED,
                                      sizeof(time_queued), &time_queued, nullptr);
        if (err == CL_SUCCESS) {
            BOOST_CHECK_GT(time_queued, 0);

            cl_ulong time_submit = 0;
            err = clGetEventProfilingInfo(kernel_event, CL_PROFILING_COMMAND_SUBMIT,
                                          sizeof(time_submit), &time_submit, nullptr);
            BOOST_CHECK_EQUAL(err, CL_SUCCESS);
            BOOST_CHECK_GE(time_submit, time_queued);

            cl_ulong time_start = 0;
            err = clGetEventProfilingInfo(kernel_event, CL_PROFILING_COMMAND_START,
                                          sizeof(time_start), &time_start, nullptr);
            BOOST_CHECK_EQUAL(err, CL_SUCCESS);
            BOOST_CHECK_GE(time_start, time_submit);

            cl_ulong time_end = 0;
            err = clGetEventProfilingInfo(kernel_event, CL_PROFILING_COMMAND_END,
                                          sizeof(time_end), &time_end, nullptr);
            BOOST_CHECK_EQUAL(err, CL_SUCCESS);
            BOOST_CHECK_GE(time_end, time_start);
        }
        // 如果不支持配置文件，则上面的调用会返回错误，这是正常的
    }

    // 清理资源
    err = clReleaseEvent(kernel_event);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseMemObject(buffer);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseKernel(kernel);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseProgram(program);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}